package com.jackeysun.common

import android.app.Activity
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Matrix
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import android.os.Bundle
import android.text.Spannable
import android.text.SpannableStringBuilder
import android.text.method.LinkMovementMethod
import android.text.style.ClickableSpan
import android.text.style.ImageSpan
import android.text.style.URLSpan
import android.util.Base64
import android.util.Base64.decode
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.WindowManager
import android.widget.TextView
import androidx.annotation.IdRes
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.LifecycleObserver
import androidx.viewbinding.ViewBinding
import androidx.viewbinding.ViewBindings
import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.request.RequestOptions
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import net.nightwhistler.htmlspanner.HtmlSpanner
import net.nightwhistler.htmlspanner.SpanStack
import net.nightwhistler.htmlspanner.TagNodeHandler
import net.nightwhistler.htmlspanner.handlers.ImageHandler
import net.nightwhistler.htmlspanner.handlers.LinkHandler
import org.htmlcleaner.TagNode
import java.io.IOException
import java.lang.reflect.Method
import java.util.concurrent.TimeUnit

/**
 *   Created by sunxunchao on 2021/11/17.
 */
suspend fun TextView.showRich(html: String?) {
    showRich(html, null, null)
}

suspend fun TextView.showRich(html: String?, tag: String?, handler: TagNodeHandler?) {
    val mHtmlSpanner = HtmlSpanner()
    if (!tag.isNullOrEmpty() && handler != null) {
        mHtmlSpanner.registerHandler(tag, handler)
    }
    mHtmlSpanner.registerHandler("a", AHandlerSelf())
    this.movementMethod = LinkMovementMethod.getInstance()
    this.text = html?.fromHtml(mHtmlSpanner)
}

suspend fun String.fromHtml(mHtmlSpanner: HtmlSpanner): Spannable {
    return withContext(Dispatchers.IO) {
        mHtmlSpanner.fromHtml(this@fromHtml)
    }
}

/**
 * a标签中 ”href“属性值为空的情况
 */
class AHandlerSelf : LinkHandler() {
    override fun handleTagNode(
        node: TagNode?,
        builder: SpannableStringBuilder?,
        start: Int,
        end: Int,
        stack: SpanStack
    ) {
        val href = node?.getAttributeByName("href") ?: return
        stack.pushSpan(URLSpan(href), start, end)
    }

}

class ImageClickHandler(val context: Context) : ImageHandler() {
    override fun handleTagNode(
        node: TagNode?,
        builder: SpannableStringBuilder?,
        start: Int,
        end: Int,
        stack: SpanStack?
    ) {
        super.handleTagNode(node, builder, start, end, stack)
        val clickImage = object : ClickableSpan() {
            override fun onClick(widget: View) {
                val dialog = DialogFragmentShowPic()
                val bundle = Bundle()
                val src = node?.getAttributeByName("src")
                bundle.putString("content", src)
                dialog.arguments = bundle
                dialog.show(
                    (context as FragmentActivity).supportFragmentManager,
                    "DialogFragmentJKRealTestShowPic"
                )
            }
        }
        stack?.pushSpan(clickImage, start, builder?.length ?: start)
    }
}

fun loadBitmap(context: Context, url: String?): Drawable? {
    return try {
        Glide.with(context).asDrawable().load(url).submit()
            .get(5, TimeUnit.SECONDS)
    } catch (e: IOException) {
        e.printStackTrace()
        null
    }
}

class ImageHandlerSelf(val activity: FragmentActivity, var width: Int = -1, var height: Int = -1) :
    TagNodeHandler() {
    override fun handleTagNode(
        node: TagNode?,
        builder: SpannableStringBuilder?,
        start: Int,
        end: Int,
        stack: SpanStack
    ) {

        val src = node?.getAttributeByName("src") ?: ""
        val item = "\uFFFC"
        builder?.append(item)
        val endTo = end + item.length
        Log.d("ImageHandlerSelf", "handleTagNode: start${start}, end${end}, endTo${endTo}")
        builder?.let {

            try {
                if (src.startsWith("data:image")) {
                    val decodedString = decode(src.split(",").getOrNull(1), Base64.DEFAULT)
                    val bitmap = BitmapFactory.decodeByteArray(decodedString, 0, decodedString.size)
                    val scale = (width.toFloat() / bitmap.width)
                    val resource = BitmapDrawable(activity.resources, bitmap scaleTo scale)
                    resource.setBounds(0, 0, width - 1, bitmap.height.times(scale).toInt() - 1)
                    builder.setSpan(
                        ImageSpan(resource), start, endTo,
                        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
                    )
                } else {
                    val file =
                        Glide.with(activity).asFile().load(src).submit().get(5, TimeUnit.SECONDS)
                    val options = BitmapFactory.Options()
                    options.inJustDecodeBounds = true
                    BitmapFactory.decodeFile(file.absolutePath, options)
                    val w = options.outWidth
                    val h = options.outHeight
                    if (height == -1) {
                        val factor = if (h == 0) {
                            3 / 2f
                        } else {
                            w / h.toFloat()
                        }
                        height = (width / factor).toInt()
                    }
                    if (width == -1) {
                        val factor = if (h == 0) {
                            3 / 2f
                        } else {
                            w / h.toFloat()
                        }
                        width = (height * factor).toInt()
                    }
                    val glideOptions = RequestOptions()
                        .skipMemoryCache(true)
                        .diskCacheStrategy(DiskCacheStrategy.NONE)
                        .centerInside()
                        .override(width, height)
                    val resource =
                        Glide.with(activity).asDrawable().load(file).apply(glideOptions).submit()
                            .get(5, TimeUnit.SECONDS)
                    resource.setBounds(0, 0, width - 1, height - 1)
                    builder.setSpan(
                        ImageSpan(resource), start, endTo,
                        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
                    )
                }
                val clickImage = object : ClickableSpan() {
                    override fun onClick(widget: View) {
                        val dialog = DialogFragmentShowPic()
                        val bundle = Bundle()
                        bundle.putString("content", src)
                        dialog.arguments = bundle
                        dialog.show(
                            activity.supportFragmentManager,
                            "DialogFragmentJKRealTestShowPic"
                        )
                    }
                }
                builder.setSpan(
                    clickImage, start, endTo,
                    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
                )

            } catch (e: Throwable) {
                e.printStackTrace()
            }
        }

    }
}

private infix fun Bitmap.scaleTo(ratio: Float): Bitmap? {
    val width = this.width
    val height = this.height
    val matrix = Matrix()
    matrix.preScale(ratio, ratio)
    val newBM = Bitmap.createBitmap(this, 0, 0, width, height, matrix, false)
    if (newBM == this) {
        return newBM
    }
    this.recycle()
    return newBM
}

inline fun <reified T : Activity> Context.go(
    to: T,
   noinline block: ((i: Intent) -> Unit)? = null
) {
    val intent = Intent(this, to::class.java)
    block?.invoke(intent)
    if (this !is Activity) {
        intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
    }
    startActivity(intent)
}

inline fun <reified T : Activity> Context.goto(
    to: T,
   noinline block: (Intent.() -> Unit)? = null
) {
    val intent = Intent(this, to::class.java)
    block?.invoke(intent)
    if (this !is Activity) {
        intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
    }
    startActivity(intent)
}

//inline fun <reified T : Activity> Activity.go(
//    to: T,
//    requestCode: Int
//) = go(to, requestCode) {}

inline fun <reified T : Activity> Activity.go(
    to: T,
    requestCode: Int = 0,
    noinline block: (Intent.() -> Unit)? = null
) {
    val intent = Intent(this, to::class.java)
    block?.invoke(intent)
    startActivityForResult(intent, requestCode)
}

inline infix fun <reified T : View> View.`$`(@IdRes id: Int): T? = this.findViewById(id)

fun Activity.setWindowBackgroundAlpha(bgAlpha: Float) {
    val lp = this.window.attributes
    lp.alpha = bgAlpha //[0.0-1.0]
    if (bgAlpha == 1f) {
        this.window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
    } else {
        this.window.addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
    }
    this.window.attributes = lp
}

inline fun <reified VB : ViewBinding> View.binding(): VB {
    val bindMethod: Method = VB::class.java.getMethod("bind", View::class.java)
    return bindMethod.invoke(null, this@binding) as VB
}

fun <VB : ViewBinding> Fragment.binding(inflate: (LayoutInflater) -> VB) = lazy {
     inflate(layoutInflater)
}

fun <VB : ViewBinding> Activity.binding(inflate: (LayoutInflater) -> VB) = lazy {
    inflate(layoutInflater).apply { setContentView(root) }
}

//fun <VB : ViewBinding> Fragment.binding(inflate: (LayoutInflater) -> VB) = lazy {
//    inflate(layoutInflater).apply { onCreateView() }
//}


